#include "PrecompiledHeaders.h"
#include "PlayState.h"
#include "MenuInGame.h"

#define MAX_VELOCITY 50.0

std::vector<Player*> PlayState::players(0);
Player *PlayState::main_player = NULL;
Player *PlayState::ghost = NULL;
GameSession *PlayState::main_player_session = NULL;
FILE *PlayState::out_file = NULL;

PlayState::PlayState(void)
{
    camera = NULL;
    overlays_enabled = true;
    in_replay = false;
}

PlayState::~PlayState(void) {}

/*
 * Grab state pointers
 */
void PlayState::getStatePointers()
{
    menu = (MenuInGame *)((MenuState *)findByName("in_game_menu"));
}

/*
 * As we start playing a level, assign input devices to players, check we have
 * enough players, set up a camera, skybox, ogre newt and the HUD. Call
 * startPlaying so that different play states can add anything extra they need
 */
void PlayState::enter(void)
{
    hud_overlay = NULL;
    stats_overlay = NULL;
    countdown_overlay = NULL;
    enterExtras();
    // set up players and camera
    initialisePlayers();
    if(players.size() < 1)
        throw new Ogre::Exception(1002, "No players in playstate!\n", "PlayState::enter");
    if(!main_player)
        throw new Ogre::Exception(1002, "No main player in playstate!\n", "PlayState::enter");
    main_player->setMainPlayer(true);
    time_until_user_can_control = getTimeUntilUserCanControl();
    setCamera(resources->current_camera);
    
    
    // reset the players ready for next time
    std::vector<Player*>::iterator it; 
    for(it = players.begin(); it != players.end(); it++)
        (*it)->reset();
    
    
    // set up sky box
    skybox_node = resources->scene_manager->getSkyBoxNode();
    
    // set up OgreNewt
    resources->ogre_newt->setLeaveWorldCallback<PlayState>(&PlayState::fallOut, this);
	
    // set up HUD and other overlays
    timer_goal = resources->current_level->seconds_for_level;
    initialiseHUD();
    initialiseCountdownOverlay();
    initialiseExtraOverlays();
    initialisePickupOverlays();
  
    // set up other bits
    stop_playing = false;
    ogre_time = 0;
    ogre_frame_count = 0;
    ogre_newt_time = 0;
    startPlaying();
    
    simulated_time = 0;
}

/*
 * Set up HUD
 */
void PlayState::initialiseHUD()
{
    //display HUD overlays
	std::string str;
	std::stringstream ss;
	Ogre::OverlayManager* overlay_manager = Ogre::OverlayManager::getSingletonPtr();
	Ogre::OverlayElement *hud_lives, *hud_timer, *hud_score;
	hud_overlay = overlay_manager->getByName("HudOverlay");
    if(overlays_enabled) hud_overlay->show();
    stats_overlay = overlay_manager->getByName("StatsOverlay");
    stats_overlay->hide();
    
    hud_lives = overlay_manager->getOverlayElement("Hud/Lives/Text");
	ss << PlayState::main_player->getSession()->getNumLives();
	str = ss.str();
	hud_lives->setCaption(str);	
	ss.str("");
    
    hud_score = overlay_manager->getOverlayElement("Hud/Score/Text");
    ss.fill('0');
    ss.width(6);
	ss << PlayState::main_player->getSession()->getLevelScore();
	str = ss.str();
	hud_score->setCaption(str);
	ss.str("");
    
    hud_timer = overlay_manager->getOverlayElement("Hud/Timer");
	int mins, secs, h_secs;
	mins = (int)(timer_goal / 60);
	secs = (int)timer_goal;
	h_secs = (int)(timer_goal * 100);
	secs -= mins * 60;
	h_secs -= (secs * 100) + (mins * 6000);
	std::stringstream smins, ssecs, shsecs;
	smins.fill('0');
	smins.width(2);
	smins << mins;
    ssecs.fill('0');
	ssecs.width(2);
	ssecs << secs;
    shsecs.fill('0');
	shsecs.width(2);
	shsecs << h_secs;
	str = "" + smins.str() + ":" + ssecs.str() + "." + shsecs.str();
    hud_timer->setCaption(str);
}

/*
 * Initialise countdown overlay
 */
void PlayState::initialiseCountdownOverlay()
{
    Ogre::OverlayManager * overlay_manager = Ogre::OverlayManager::getSingletonPtr();
    countdown_overlay = overlay_manager->getByName("CountdownOverlay");
}

void PlayState::initialisePickupOverlays() {
    num_pickups_active = 0;
    Ogre::OverlayManager* overlay_manager = Ogre::OverlayManager::getSingletonPtr();
    pickup_overlay = overlay_manager->getByName("PickupOverlay");   
    Ogre::OverlayElement* pu_size = overlay_manager->getOverlayElement("Pickup/Size");
    pu_size->hide();    
    Ogre::OverlayElement* pu_invert = overlay_manager->getOverlayElement("Pickup/Invert");
    pu_invert->hide();
    Ogre::OverlayElement* pu_speed = overlay_manager->getOverlayElement("Pickup/Speed");
    pu_speed->hide();
    Ogre::OverlayElement* pu_sensitivity = overlay_manager->getOverlayElement("Pickup/Sensitivity");
    pu_sensitivity->hide();
    pickup_overlay->show();
}

/*
 * Uninitialise everything in the level
 */
void PlayState::exit(void)
{
    if (out_file) fclose(out_file);

    std::vector<Player*>::iterator it; 
    for(it = players.begin(); it != players.end(); it++) {
        (*it)->setPlayState(this); // needed to reset pickups
        (*it)->getSession()->setReplay(false);
        (*it)->reset();
        (*it)->changeInputDevice(NULL);
        (*it)->setPlayState(NULL);
    }
        
    // remove the player's listeners
    if(main_player)
    {
        main_player->usePod(false);
        main_player_session = main_player->getSession();
    }
    else main_player_session = NULL;
    
    //remove the camera
    setCamera(NULL);
    
    // remove the sky box
    skybox_node = NULL;
    
    // remove the overlay
    if(hud_overlay) hud_overlay->hide();
    if(stats_overlay) stats_overlay->hide();
    if(countdown_overlay) countdown_overlay->hide();
    
    // stop ogre newt
    OgreNewt::Debugger::getSingleton().deInit();
    resources->ogre_newt->setLeaveWorldCallback(NULL);
    
    in_replay = false;
}

bool PlayState::keyReleased(const OIS::KeyEvent & e) {return true;}
bool PlayState::mouseMoved(const OIS::MouseEvent & e) {return true;}
bool PlayState::mousePressed(const OIS::MouseEvent & e, OIS::MouseButtonID ID) {return true;}
bool PlayState::mouseReleased(const OIS::MouseEvent & e, OIS::MouseButtonID ID) {return true;}

/*
 * Update everything for this frame
 */
bool PlayState::frameStarted(const Ogre::FrameEvent &evt)
{
    // Countdown timer
    Ogre::Real frame_time = play_speed * evt.timeSinceLastFrame;
    if(ogre_frame_count < 1)
	{
        time_until_user_can_control = getTimeUntilUserCanControl();
		ogre_frame_count++;
		return true;
	}
    
    
    // update timers etc
    // Check we haven't run out of time, otherwise decrement
    if(timer_goal < 0)
    {
        if(PlayState::main_player->getSession()->removeLife())
		{
		    // Respawn with reset scores and time
		    PlayState::main_player->getSession()->resetLevelScore();
		    updateScoreOverlay();
		    main_player->reset();
            time_until_user_can_control = getTimeUntilUserCanControl();
            timer_goal = resources->current_level->seconds_for_level;
            camera->reset();
		}
		else
		{
		    // Player has failed level
		    main_player->getSession()->setState(ssFAILED);
			stop_playing = true;
		}
    }
    else if(time_until_user_can_control < 0) {
        timer_goal -= frame_time;
    }
    
    // update physics
    if(time_until_user_can_control <= 0)
    {
        // update all players
        ogre_newt_time += frame_time;
        float ogre_newt_update_time;
        while(!stop_playing && ogreNewtNeedsUpdate())
        {
            ogre_newt_update_time = getOgreNewtUpdateTime();
            std::vector<Player*>::iterator it; 
            for(it = players.begin(); it != players.end(); it++)
                (*it)->update(ogre_newt_update_time );
            resources->ogre_newt->update(ogre_newt_update_time );
            ogre_newt_time -= ogre_newt_update_time;
            simulated_time += ogre_newt_update_time;
            setStopPlaying();
        }
        ogre_time += frame_time;
    }
    else
    {
        std::vector<Player*>::iterator it; 
        for(it = players.begin(); it != players.end(); it++)
            (*it)->initialiseDevice();
    }
    
    // Set camera
    if(camera)
    {
     camera->updateCamera(frame_time);
    
    // Set skybox
    skybox_node->setOrientation(camera->getSkyOrientation());
    }
    
    // update HUD and overlays
    updateHUD(frame_time);
    updateCountdownOverlay();
    updateExtraOverlays();
    
    // Update main player session
    if(main_player && main_player->getSession()) main_player->getSession()->setTimeLeft(timer_goal);
    
    time_until_user_can_control -= frame_time;
    ogre_frame_count++;

    // query joystick. Should be in a callback but its late and i can't be arsed
    Joystick *j = dynamic_cast<Joystick*>(resources->current_device);
    if(j && resources->joystick->quit())
    {
        menu->setLayout((LayoutType)PAUSE);
        pushGameState(findByName("in_game_menu"));
    }
    if(j && resources->joystick->triggerPressed())
    {
        FirstPersonCamera *fp = dynamic_cast<FirstPersonCamera*>(resources->current_camera);
        if(fp)
        {
            setCamera(resources->third_person_camera);
            resources->current_camera = (CameraControl *)resources->third_person_camera;
        }
        else
        {
            setCamera(resources->first_person_camera);
            resources->current_camera = (CameraControl *)resources->first_person_camera;
        }
    }
    return true;
}

void PlayState::updateHUD(Ogre::Real timeSinceLastFrame)
{
    // update hud
    std::string str;
    std::stringstream ss;
    
    //update HUD timer
    Ogre::OverlayManager* overlay_manager = Ogre::OverlayManager::getSingletonPtr();
    Ogre::OverlayElement* hud_timer = overlay_manager->getOverlayElement("Hud/Timer");
    int mins, secs, h_secs;
    
    std::string string;
    std::stringstream sstream;
    Ogre::OverlayElement* hud_lives = overlay_manager->getOverlayElement("Hud/Lives/Text");
    sstream << PlayState::main_player->getSession()->getNumLives();
    string = sstream.str();
    hud_lives->setCaption(string);
    
    mins = (int)(timer_goal / 60);
    secs = (int)timer_goal;
    h_secs = (int)(timer_goal * 100);
    secs -= mins * 60;
    h_secs -= (secs * 100) + (mins * 6000);
    std::stringstream smins, ssecs, shsecs;
    smins.fill('0');
    smins.width(2);
    smins << mins;
    ssecs.fill('0');
    ssecs.width(2);
    ssecs << secs;
    shsecs.fill('0');
    shsecs.width(2);
    shsecs << h_secs;
    str = "" + smins.str() + ":" + ssecs.str() + "." + shsecs.str();
    hud_timer->setCaption(str);
    
    //update FPS
    Ogre::OverlayElement* stats_FPS = overlay_manager->getOverlayElement("Stats/FPS");
    ss << resources->render_window->getLastFPS();
    str = "FPS: " + ss.str();
    stats_FPS->setCaption(str);
    ss.str("");
    
    //update triangle count
    Ogre::OverlayElement* stats_triangles = overlay_manager->getOverlayElement("Stats/TriangleCount");
    ss << resources->render_window->getTriangleCount();
    str = "Triangles: " + ss.str();
    stats_triangles->setCaption(str);
    ss.str("");
}

/*
 * Update overlay. Check if it should be visible or not, then update text
 */
void PlayState::updateCountdownOverlay()
{
    if(countdown_overlay->isVisible() && time_until_user_can_control < -0.5)
        countdown_overlay->hide();
    else if(!countdown_overlay->isVisible() && time_until_user_can_control >= -0.5)
        if(overlays_enabled) countdown_overlay->show();
    if(countdown_overlay->isVisible())
    {
        Ogre::OverlayManager * overlay_manager = Ogre::OverlayManager::getSingletonPtr();
        countdown = overlay_manager->getOverlayElement("Countdown/Text");
        //countdown->setAlignment(Ogre::TextAreaOverlayElement::Center);
        countdown->setCaption(getCountdownText());
        countdown->setLeft(0.5 - (Ogre::Real(getCountdownText().length()) / 10));
    }
}

void PlayState::updateLifeOverlay()
{
	std::stringstream ss;
	Ogre::OverlayManager* overlay_manager = Ogre::OverlayManager::getSingletonPtr();
	Ogre::OverlayElement *hud_lives;

    hud_lives = overlay_manager->getOverlayElement("Hud/Lives/Text");
	ss << main_player->getSession()->getNumLives();
	hud_lives->setCaption(ss.str());

}

void PlayState::updateScoreOverlay()
{
	std::stringstream ss;
	Ogre::OverlayManager* overlay_manager = Ogre::OverlayManager::getSingletonPtr();
	Ogre::OverlayElement *hud_score;	
    hud_score = overlay_manager->getOverlayElement("Hud/Score/Text");
    ss.fill('0');
    ss.width(6);
	ss << main_player->getSession()->getLevelScore();
	hud_score->setCaption(ss.str());
}

void PlayState::showSizeOverlay(int id) {
    ++num_pickups_active;
    std::string instance_name;
    std::stringstream ss;
    ss << id;
    instance_name = ss.str();
    Ogre::OverlayManager* overlay_manager = Ogre::OverlayManager::getSingletonPtr();
    Ogre::OverlayElement* pu_size = overlay_manager->getOverlayElement("Pickup/Size")->clone(instance_name);
    pickup_overlay->add2D(dynamic_cast<Ogre::OverlayContainer*>(pu_size));
    struct active_pickup ap = {id, pu_size};
    active_pickups.push_back(ap);
    pu_size->setTop(0.8);
    pu_size->setLeft(0.83 - (num_pickups_active - 1) * .11);
    if(overlays_enabled && !in_replay) pu_size->show();
}

void PlayState::hideSizeOverlay(int id) {
    --(this->num_pickups_active);
    Ogre::OverlayManager* overlay_manager = Ogre::OverlayManager::getSingletonPtr();
    Ogre::OverlayElement* pu_size;
    struct active_pickup ap;
    std::vector<struct active_pickup>::iterator it = active_pickups.end();
    std::vector<struct active_pickup>::iterator it_index;
    int i = 0, index = (int) active_pickups.size();
    for(it = active_pickups.begin(); it != active_pickups.end(); ++it) {
        ap = *it;
        if(ap.id == id) {
            pu_size = ap.overlay;
            index = i;
            it_index = it;
        }
        if(i > index) {
            ap.overlay->setLeft(0.83 - (i - 1) * .11);
        }
        ++i;
    }
    active_pickups.erase(it_index);
    std::string instance_name;
    std::stringstream ss;
    ss << id;
    instance_name = ss.str() + "/Pickup/Size";
    overlay_manager->destroyOverlayElement(instance_name);
}

void PlayState::showInvertOverlay(int id) {
    ++num_pickups_active;
    std::string instance_name;
    std::stringstream ss;
    ss << id;
    instance_name = ss.str();
    Ogre::OverlayManager* overlay_manager = Ogre::OverlayManager::getSingletonPtr();
    Ogre::OverlayElement* pu_invert = overlay_manager->getOverlayElement("Pickup/Invert")->clone(instance_name);
    pickup_overlay->add2D(dynamic_cast<Ogre::OverlayContainer*>(pu_invert));
    struct active_pickup ap = {id, pu_invert};
    active_pickups.push_back(ap);
    pu_invert->setTop(0.8);
    pu_invert->setLeft(0.83 - (num_pickups_active - 1) * .11);
    if(overlays_enabled && !in_replay) pu_invert->show();
}

void PlayState::hideInvertOverlay(int id) {
    --num_pickups_active;
    Ogre::OverlayManager* overlay_manager = Ogre::OverlayManager::getSingletonPtr();
    Ogre::OverlayElement* pu_invert;
    struct active_pickup ap;
    std::vector<struct active_pickup>::iterator it = active_pickups.end();
    std::vector<struct active_pickup>::iterator it_index;
    int i = 0, index = (int) active_pickups.size();
    for(it = active_pickups.begin(); it != active_pickups.end(); ++it) {
        ap = *it;
        if(ap.id == id) {
            pu_invert = ap.overlay;
            index = i;
            it_index = it;
        }
        if(i > index) {
            ap.overlay->setLeft( 0.83 - (i - 1) * .11);
        }
        ++i;
    }
    active_pickups.erase(it_index);
    std::string instance_name;
    std::stringstream ss;
    ss << id;
    instance_name = ss.str() + "/Pickup/Invert";
    overlay_manager->destroyOverlayElement(instance_name);
}

void PlayState::showSpeedOverlay(int id) {
    ++num_pickups_active;
    std::string instance_name;
    std::stringstream ss;
    ss << id;
    instance_name = ss.str();
    Ogre::OverlayManager* overlay_manager = Ogre::OverlayManager::getSingletonPtr();
    Ogre::OverlayElement* pu_speed = overlay_manager->getOverlayElement("Pickup/Speed")->clone(instance_name);
    pickup_overlay->add2D(dynamic_cast<Ogre::OverlayContainer*>(pu_speed));
    struct active_pickup ap = {id, pu_speed};
    active_pickups.push_back(ap);
    pu_speed->setTop(0.8);
    pu_speed->setLeft(0.83 - (num_pickups_active - 1) * .11);
    if(overlays_enabled && !in_replay) pu_speed->show();
}

void PlayState::hideSpeedOverlay(int id) {
    --num_pickups_active;
    Ogre::OverlayManager* overlay_manager = Ogre::OverlayManager::getSingletonPtr();
    Ogre::OverlayElement* pu_speed;
    struct active_pickup ap;
    std::vector<struct active_pickup>::iterator it = active_pickups.end();
    std::vector<struct active_pickup>::iterator it_index;
    int i = 0, index = (int) active_pickups.size();
    for(it = active_pickups.begin(); it != active_pickups.end(); ++it) {
        ap = *it;
        if(ap.id == id) {
            pu_speed = ap.overlay;
            index = i;
            it_index = it;
        }
        if(i > index) {
            ap.overlay->setLeft(0.83 - (i - 1) * .11);
        }
        ++i;
    }
    active_pickups.erase(it_index);
    std::string instance_name;
    std::stringstream ss;
    ss << id;
    instance_name = ss.str() + "/Pickup/Speed";
    overlay_manager->destroyOverlayElement(instance_name);
}

void PlayState::showSensitivityOverlay(int id) {
    ++num_pickups_active;
    std::string instance_name;
    std::stringstream ss;
    ss << id;
    instance_name = ss.str();
    Ogre::OverlayManager* overlay_manager = Ogre::OverlayManager::getSingletonPtr();
    Ogre::OverlayElement* pu_sensitivity = overlay_manager->getOverlayElement("Pickup/Sensitivity")->clone(instance_name);
    pickup_overlay->add2D(dynamic_cast<Ogre::OverlayContainer*>(pu_sensitivity));
    struct active_pickup ap = {id, pu_sensitivity};
    active_pickups.push_back(ap);
    pu_sensitivity->setTop(0.8);
    pu_sensitivity->setLeft(0.83 - (num_pickups_active - 1) * .11);
    if(overlays_enabled && !in_replay) pu_sensitivity->show();
}

void PlayState::hideSensitivityOverlay(int id) {
    --num_pickups_active;
    Ogre::OverlayManager* overlay_manager = Ogre::OverlayManager::getSingletonPtr();
    Ogre::OverlayElement* pu_sensitivity;
    struct active_pickup ap;
    std::vector<struct active_pickup>::iterator it = active_pickups.end();
    std::vector<struct active_pickup>::iterator it_index;
    int i = 0, index = (int) active_pickups.size();
    for(it = active_pickups.begin(); it != active_pickups.end(); ++it) {
        ap = *it;
        if(ap.id == id) {
            pu_sensitivity = ap.overlay;
            index = i;
            it_index = it;
        }
        if(i > index) {
            ap.overlay->setLeft(0.83 - (i - 1) * .11);
        }
        ++i;
    }
    active_pickups.erase(it_index);
    std::string instance_name;
    std::stringstream ss;
    ss << id;
    instance_name = ss.str() + "/Pickup/Sensitivity";
    overlay_manager->destroyOverlayElement(instance_name);
}
	
std::string PlayState::getCountdownText()
{
    if(time_until_user_can_control > 2) return "3";
    if(time_until_user_can_control > 1) return "2";
    if(time_until_user_can_control > 0) return "1";
    return "GO!";
}

/*
 * Check to see if this level has been finished
 */
bool PlayState::frameEnded(const Ogre::FrameEvent &evt)
{
    if (stop_playing) {
        stopPlaying();
    }
    return true;
}

/*
 * Pause the game: remove all Ogre listeners
 */
bool PlayState::pause()
{
    std::vector<Player*>::iterator it; 
    for(it = players.begin(); it != players.end(); it++)
        (*it)->setPlayState(NULL);
    main_player->usePod(false);
    hud_overlay->hide();
    stats_visible = stats_overlay->isVisible();
    stats_overlay->hide();
    countdown_overlay->hide();
    return true;
}

/*
 * Resume the game: add all Ogre listeners
 */
void PlayState::resume()
{
    // Inspect the menu state, as pause gets pushed ontop
    std::vector<Player*>::iterator it;
	switch(menu->getState())
    {
		case lsRESUME:
            for(it = players.begin(); it != players.end(); it++)
                (*it)->setPlayState(this);
			main_player->usePod(true);
			if(overlays_enabled) hud_overlay->show();
			if(stats_visible && overlays_enabled) stats_overlay->show();
			//setCamera(resources->current_camera);
			return;

		case lsQUIT:
			resources->current_camera->reset();
            for(it = players.begin(); it != players.end(); it++)
            {
                (*it)->stopRecording();
				(*it)->changeInputDevice(NULL);
			}
			main_player->getSession()->setState(ssQUIT);
			popGameState();
			return;
        default:
            break;
	}
}

/*
 * Play the requested sound 
 */
void PlayState::playSound(SourceIndex i)
{
    resources->audio->playSource(i);
}

/*
 * When the ball falls out of the world's bounding box
 */
void PlayState::fallOut(OgreNewt::Body *me)
{
    BodyType bt (me->getType());
    // CHANGE NEEDED to if the type is the current player
    if(bt.getSpecialType() == BodyType::SP_BALL)
    {
        Ball *ball = (Ball*) me->getUserData();
        if (ball->getPlayer()->isMainPlayer())
        {
            resources->audio->playSource(AUDIO_FALLOUT);
            
            // Take off a life and reset score
		    if(PlayState::main_player->getSession()->removeLife())
		    {
		        playerFallout();
		    }
		    else
		    {
		        // Player has failed level
		        main_player->getSession()->setState(ssFAILED);
			    stop_playing = true;
		    }
		}
    }
    else
    {
        Ogre::SceneNode *scene_node = dynamic_cast<Ogre::SceneNode*>(me->getOgreNode());
        if (scene_node)
        {
            Ogre::SceneNode::ObjectIterator obj = scene_node->getAttachedObjectIterator();
            while (obj.hasMoreElements())
            {
                Ogre::MovableObject *m_obj = obj.getNext();
                m_obj->setVisible(false);
            }
        }
    }    
}

/*
 * Return the main player game session pointer
 */
GameSession *PlayState::getGameSession()
{
    return main_player->getSession();
}

/*
 * Add time to the timer
 */
void PlayState::addTime(Ogre::Real t)
{
    timer_goal += t;
}

/*
 * Given a collision normal and ball direction, simulate the collision
 */
void PlayState::simulateAcceleration(Ogre::Vector3 normal, Ogre::Vector3 ball_direction, float strength)
{
    if(resources->pod != NULL)
    {
        // rotate based on cameras direction
        Ogre::Quaternion rotation = camera->getDirection().getRotationTo(camera->getInitialDirection());
        //adjust for pitch and roll
        rotation = rotation - Ogre::Quaternion(-camera->getOriginalPitch(), camera->getRight());
        resources->pod->simulateAcceleration((rotation * normal) * strength);
    }
}

void PlayState::addDownwardMovement()
{
    if(resources->pod != NULL)
    {
        resources->pod->simulateAcceleration(Ogre::Vector3(0, -3, 0));
    }
}

void PlayState::homePod()
{
    if(resources->pod != NULL)
    {
        resources->pod->setRollAndPitch(0.0, 0.0);
    }
}

/*
 * Are we using the pod?
 */
bool PlayState::isPodControlOn()
{
    return resources->pod_control;
}

/*
 * Ball has collided with something
 */
void PlayState::ballCollision(float volume)
{
    resources->audio->setSourceGain(AUDIO_COLLISION, volume/MAX_VELOCITY);
    resources->audio->playSource(AUDIO_COLLISION);
}

/*
 * Add a player to play with
 */
void PlayState::addPlayer(Player *player, bool isMain)
{
    players.push_back(player);
    if(isMain) {
        if(main_player != NULL)
            throw new Ogre::Exception(1003, "Main player already defined!\n", "PlayState::addPlayer");
        else main_player = player;
    }
}

/*
 * Remove all current players
 */
void PlayState::removeAllPlayers()
{
    std::vector<Player*>::iterator it; 
    for(it = players.begin(); it != players.end(); it++)
    {
        if((*it) != main_player) {
            delete (*it);
        }
    }
    players.clear();
    main_player = NULL;
    ghost = NULL;
}

/*
 * Set the camera that we will rendered through
 */
void PlayState::setCamera(CameraControl *c)
{
    if(camera)
    {
        camera->unregisterPlayer();
        camera->usePod(NULL);
    }
    camera = c;
    if(camera)
    {
        camera->registerPlayer(main_player, resources->ogre_newt);
        camera->usePod(resources->pod);
        camera->reset();
    }
}

/*
 * Return the elapsed play time
 */
Ogre::Real PlayState::getPlayDuration()
{
    return simulated_time;
}
